#!/usr/bin/env python

# Copyright 2009 David Lee Miller
#
# This file is part of POSSM (Python Open Source Scanning Microscopy).
#
# POSSM is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# POSSM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License         
# along with POSSM.  If not, see <http://www.gnu.org/licenses/>.
#                                                                           
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


import sys
if '--fake' in sys.argv or '-f' in sys.argv: fake=True
else: fake=False

from controller import Queue,os
import shared.datatransfer as dt
import shared.worldsettings as ws
import controller.parallelppdev as pdev

if fake:
	from controller.fakeInterface import devices
	import controller.fakeID as iD
	pport = None
else:
	from controller.comediInterface import devices
	import controller.implementDrivers as iD
	pport = pdev.Parallel()
	#pport = None

pid = os.getpid()
os.system('chrt -f -p 1 '+str(pid)) #set the realtime priority of the controller

q1 = Queue.Queue()
q2 = Queue.Queue()
q3 = Queue.Queue()
q4 = Queue.Queue()
q5 = Queue.Queue()

xmove_zpos = iD.AnalogIO(devices[ws.ZPOS[0]],devices[ws.XCHAN[0]],ws.ZPOS[1],ws.XCHAN[1],'xmove')
ymove = iD.AnalogOutput(devices[ws.YCHAN[0]],ws.YCHAN[1],'ymove')
tip_current = iD.AnalogInput(devices[ws.TIP_CURRENT[0]],ws.TIP_CURRENT[1])
zpos = iD.AnalogInput(devices[ws.ZPOS[0]],ws.ZPOS[1])

tip = iD.AnalogOutput(devices[ws.TIP_VOLTS[0]],ws.TIP_VOLTS[1],'tip volts')
io_tip = iD.AnalogIO(devices[ws.TIP_CURRENT[0]],devices[ws.TIP_VOLTS[0]],ws.TIP_CURRENT[1],ws.TIP_VOLTS[1],'iotip')
xoff = iD.AnalogOutput(devices[ws.XOFF_CHAN[0]],ws.XOFF_CHAN[1],'x offset')
yoff = iD.AnalogOutput(devices[ws.YOFF_CHAN[0]],ws.YOFF_CHAN[1],'y offset')
zoff = iD.AnalogOutput(devices[ws.ZOFF_CHAN[0]],ws.ZOFF_CHAN[1],'z offset')
zplane = iD.AnalogOutput(devices[ws.ZPLANE_CHAN[0]],ws.ZPLANE_CHAN[1],'z plane')

dOut = iD.DigitalOutput(devices[0])
dOut.setBits([(ws.HOLD,1),(ws.RETRACT,1)])

class DaemonServer(object):
	
	analog_io = {'xoff':xoff,'yoff':yoff,'zoff':zoff,'ymove':ymove,'xmove_zpos':xmove_zpos,'tip':tip,'zpos':zpos,'tip_current':tip_current,'zplane':zplane,'io_tip':io_tip}
	digital_io = {'pport':pport,'dOut':dOut}
	paramsq = q1
	dataq = q2
	ivq = q3
	auxq = q4
	cmdq = q5
	queues = {'_paramsq':paramsq,'_dataq':dataq,'_ivq':ivq,'_inq':auxq,'_outq':cmdq}
	pt0 = ws.PORT_CONTROLLER[0]
	pt1 = ws.PORT_CONTROLLER[1]
	pt2 = ws.PORT_CONTROLLER[2]
	pt3 = ws.PORT_CONTROLLER[3]
	pt4 = ws.PORT_CONTROLLER[4]
	STM_PREFIX = ws.STM_PREFIX
	
	def __init__(self):
		self._clearQueue(self.paramsq)
		self.Parameters = dt.SocketCommands(self.pt0)
		dt.DataCollector(self.Parameters,self.paramsq,daemon=True)
		self.Data = dt.SocketCommands(self.pt1)
		dt.DataDispenser(self.Data,self.dataq,daemon=True)
		self.IV = dt.SocketCommands(self.pt2)
		dt.DataCollector(self.IV,self.ivq,daemon=True)
		self.Aux = dt.SocketCommands(self.pt3)
		dt.DataCollector(self.Aux,self.auxq,daemon=True)
		self.Cmd = dt.SocketCommands(self.pt4)
		dt.CmdDispenser(self.Cmd,self.cmdq,True)
		self.run()
			
	def WaitForScan(self):
		scan = None
		while 1:
			print 'waiting for scan....'
			self.cmdq.put('waiting for scan...')
			scan = self.paramsq.get(block=True)
			self._cleanQueues()
			print 'scan received'
			self.cmdq.put('Scan-type \"%s\" received'%scan.package.TYPE)
			#self.cmdq.put('send go to start ('+ws.SEND_GO+'), abort ('+ws.SEND_ABORT+') to quit')
			self.cmdq.put('Proceed with scan? (y/n)')
			while 1:
				go = self.auxq.get()
				if go == 'y' or go == 'go': break
				elif go == 'n' or go == 'abort': break
			self._cleanQueues()
			scan._getMethods(self.queues,self.analog_io,self.digital_io)
			if go == 'y' or go == 'go':
				scan._doScan()
				if 'NAME' in dir(scan.im.package):
					self.cmdq.put(scan.im.package.NAME[0])
					num = self.acquireNumber()
					self.cmdq.put('Current Scan Number: %s%s'%(self.STM_PREFIX,num))
					self.cmdq.put('%s scan Completed!'%scan.im.package.TYPE)
				else: self.cmdq.put('Scan Completed!')
			elif go == 'n' or go == 'abort':
				if 'NAME' in dir(scan.im.package):
					self.cmdq.put('%s Aborted :('%scan.im.package.NAME[0])
				else: self.cmdq.put('Scan Aborted :(')
			self._clearQueue(self.paramsq)
			
	
	def acquireNumber(self):
		'''
		Retrieves a number from the number file CurrentScan and
		updates the file to the new current scan number.
		
		'''
		fh = open('CurrentScan','r')
		ret = fh.read()
		fh.close()
		return ret
	
	def _clearQueue(self, queue):
		queue.queue.clear()
	
	def _cleanQueues(self):
		self._clearQueue(self.paramsq)
		self._clearQueue(self.dataq)
		self._clearQueue(self.ivq)
		self._clearQueue(self.auxq)
		self._clearQueue(self.cmdq)
	
	def run(self):
		self.WaitForScan()



def main():
	DaemonServer()


if __name__ == '__main__': main()
